type FilterOptional<T> = Pick<
  T,
  Exclude<
    {
      [K in keyof T]: T extends Record<K, T[K]> ? K : never
    }[keyof T],
    undefined
  >
>

type FilterNotOptional<T> = Pick<
  T,
  Exclude<
    {
      [K in keyof T]: T extends Record<K, T[K]> ? never : K
    }[keyof T],
    undefined
  >
>

type PartialEither<T, K extends keyof any> = {
  [P in Exclude<keyof FilterOptional<T>, K>]-?: T[P]
} & { [P in Exclude<keyof FilterNotOptional<T>, K>]?: T[P] } & {
  [P in Extract<keyof T, K>]?: undefined
}

type Object = {
  [name: string]: any
}

/**
 * 单个接口中两个属性二选一
 */
export type EitherOr<O extends Object, L extends string, R extends string> = (
  | PartialEither<Pick<O, L | R>, L>
  | PartialEither<Pick<O, L | R>, R>
) &
  Omit<O, L | R>

/**
 * 获取接口中所有value的联合类型
 */
export type ValueOf<T> = T[keyof T]

export type AnyMap = { [key: string]: any }

export class TypeUtils {
  static AllType = [
    'null',
    'undefined',
    'number',
    'string',
    'boolean',
    'function',
    'date',
    'regExp',
    'object',
    'array',
  ] as const
  /**
   * 获取数据类型
   * @param value
   * @returns
   */
  static getType(value: any): typeof TypeUtils.AllType[number] {
    const stringType = Object.prototype.toString.call(value)
    return stringType.replace(/\[object|\]|\s+/g, '').toLowerCase()
  }
}
